/**
 * 广寒宫
 * 网址:www.guanghangong.xyz
 */
package org.moon.framework.autoconfigure.exception;


import lombok.extern.slf4j.Slf4j;

import org.moon.framework.autoconfigure.springmvc.response.R;
import org.moon.framework.autoconfigure.springmvc.response.RCode;
import org.moon.framework.autoconfigure.exception.domain.MoonException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.Servlet;

/**
 * 错误处理
 * @author moon
 */
@Slf4j
@Configuration
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@RestControllerAdvice
public class ExceptionAutoConfiguration {

	public ExceptionAutoConfiguration(){}

	@ResponseStatus(value = HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
		logError("methodArgumentNotValidException", e.getMessage(), e);
		String error = e.getBindingResult().getAllErrors().stream().findFirst()
				.map(ObjectError::getDefaultMessage).orElse("");
		return R.fail(HttpStatus.BAD_REQUEST.value(), error);
	}

	@ResponseStatus(value = HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MissingServletRequestParameterException.class)
	public R handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
		logError("missingServletRequestParameterException", e.getMessage(),e);
		return R.fail(HttpStatus.BAD_REQUEST.value(), String.format("参数%s未传", e.getParameterName()));
	}

	@ResponseStatus(value = HttpStatus.UNSUPPORTED_MEDIA_TYPE)
	@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
	public R handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
		logError("httpMediaTypeNotSupportedException", e.getMessage(), e);
		return R.fail(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), String.format("媒体类型%s错误", e.getContentType()));
	}


	@ResponseStatus(value = HttpStatus.METHOD_NOT_ALLOWED)
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public R handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
		logError("httpRequestMethodNotSupportedException", e.getMessage(),e);
		return R.fail(HttpStatus.METHOD_NOT_ALLOWED.value(), e.getMessage());
	}

	@ExceptionHandler(MoonException.class)
	public R handleLocException(MoonException e) {
		logError("moonException", e.getMessage(), e);
		return R.fail(e.getCode(), e.getMsg());
	}

	@ExceptionHandler(RuntimeException.class)
	public R handleRuntimeException(RuntimeException e) {
		logError("runtimeException", e.getMessage(), e);
		return R.fail(RCode.FAIL.getCode(),e.getMessage());
	}

	@ExceptionHandler(Throwable.class)
	public R handleThrowable(Throwable t) {
		logError("throwableError", t.getMessage(), t);
		return R.fail(RCode.FAIL.getCode(),t.getMessage());
	}

	void logError(String name, String msg, Throwable t) {
		log.error("error name is {}, msg is {}", name, msg, t);
	}
}